package com.source.auto.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.source.auto.model.BranchInfo;
import com.source.auto.model.ExcelTemplateInfo;
import com.source.auto.model.JsonConfigInfo;
import com.source.auto.model.ProjectInfo;
import com.source.auto.model.ServiceInfo;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * @author wangchangjie
 * @date 2025/1/15 13:39
 */

public class BizUtil {


    /**
     * 打印 匹配到的 分支信息
     *
     * @param matchedBranches 匹配分支
     * @param repoUrls        存储库 URL
     */
    public static void printInfo(List<String> matchedBranches, List<String> repoUrls) {
        LogUtil.printf("\n");
        if (matchedBranches.isEmpty()) {
            LogUtil.printf("没有找到匹配的分支");
        } else {
            LogUtil.printf("匹配到的内容：");
            for (int i = 0; i < matchedBranches.size(); i++) {
                LogUtil.printf("分支: {} 仓库地址: {}", matchedBranches.get(i),repoUrls.get(i));
            }
        }
    }

    /**
     * 刷新 JSON 配置信息
     *
     * @param repoPath .git存储库路径
     * @return {@link JsonConfigInfo }
     */
    public static ProjectInfo refreshJsonConfigInfo(String repoPath) {

        String repoUrl = GitUtil.getRepoUrl(repoPath);
        String projectName = GitUtil.getRepoNameByRepoUrl(repoUrl);
        // 解析pom文件
        List<ServiceInfo> serviceInfos = loadServiceInfo(repoPath);
        // 完善git url
        serviceInfos.forEach(f -> f.setServiceGitUrl(repoUrl));

        ProjectInfo projectInfo = new ProjectInfo();
        projectInfo.setProjectName(projectName);
        projectInfo.setProjectGitUrl(repoUrl);
        projectInfo.setServices(serviceInfos);

        // 获取本地git仓库中的分支信息
        List<String> branches = GitUtil.getGitBranches(repoPath);
        List<BranchInfo> branchInfoList = getBranchInfo(projectName, branches);
        projectInfo.setBranchInfos(branchInfoList);

        return projectInfo;
    }


    private static List<ServiceInfo> loadServiceInfo(String repoPath) {
        // 1、根据项目路径找出全部的pom.xml中的<modules>有哪些
        // 2、如果没有包含<modules>标签，则读取<project> 标签下的 <artifactId> 标签
        // 3、根据项目名称进行判断，有-api、-service、-web的默认判断成这些类型，否则则提示用户输入完成配置
        // 获取项目中所有的 pom.xml 文件
        List<File> pomFiles = FileUtil.findPomXmlFiles(repoPath);
        if (pomFiles.isEmpty()) {
            LogUtil.printf("未找到任何 pom.xml 文件，请检查项目路径 {}", repoPath);
            return Collections.emptyList();
        }

        List<ServiceInfo> list = new ArrayList<>();
        // 解析每个 pom.xml 文件
        for (File pomFile : pomFiles) {
//            LogUtil.printf("解析文件: " + pomFile.getAbsolutePath());
            ServiceInfo serviceInfo = FileUtil.analyzePomFile(pomFile);
            if (serviceInfo != null) {
                list.add(serviceInfo);
            }
        }
        return list;
    }


    /**
     * 获取分支 主合并、测试合并、开发合并 分支信息
     * TODO:可重写方法
     *
     * @param branches 分支
     * @return {@link List }<{@link BranchInfo }>
     */
    public static List<BranchInfo> getBranchInfo(String projectName, List<String> branches) {
        if (branches.isEmpty()) {
            return Collections.emptyList();
        }

        List<BranchInfo> list = new ArrayList<>();
        List<String> masterBranchList = Lists.newArrayList("i_master", "dd_master", "md_master",
            "dd_master");
        for (String masterBranch : masterBranchList) {
            BranchInfo branchInfo = analyzeEnvBranch(projectName, masterBranch, branches);
            if (branchInfo != null) {
                list.add(branchInfo);
            }
        }
        return list;
    }

    private static BranchInfo analyzeEnvBranch(String projectName, String mainBranch,
        List<String> branches) {
        if (branches.contains(mainBranch)) {
            BranchInfo branchInfo = new BranchInfo();
            // 主分支
            branchInfo.setMainBranch(mainBranch);
            // 测试分支
            String testBranch = searchEnvBranch(projectName, branches, "测试", mainBranch,
                Lists.newArrayList("*_test", "*_test_*", "*_test*", "*test*"));
            if (testBranch == null) {
                return null;
            }
            branchInfo.setTestMergeBranch(testBranch);
            // 开发分支
            String devBranch = searchEnvBranch(projectName, branches, "开发", mainBranch,
                Lists.newArrayList("*_dev", "*_dev_*", "*_dev*", "*dev*"));
            if (devBranch == null) {
                return null;
            }
            branchInfo.setDevMergeBranch(devBranch);
            return branchInfo;
        }
        return null;
    }

    /**
     * 搜索 env 分支
     *
     * @param projectName 项目名称
     * @param branches    分支
     * @param jobName     作业名称
     * @param mainBranch  main 分支
     * @param keyWords    关键词  条按照升序越来越简单 * 是模糊匹配
     * @return {@link String }
     */
    private static String searchEnvBranch(String projectName, List<String> branches, String jobName,
        String mainBranch, List<String> keyWords) {

        String searchBranch = "";

        List<String> waitSelectList = new ArrayList<>();
        boolean needMatchMainBranch = true;

        for (int i = 0; i < keyWords.size(); i++) {
            boolean finalNeedMatchMainBranch = needMatchMainBranch;
            String key = keyWords.get(i);

            Boolean leftLike = key.startsWith("*");
            Boolean rightLike = key.endsWith("*");

            if (leftLike) {
                key = key.substring(1);
            }
            if (rightLike) {
                key = key.substring(0, key.length() - 1);
            }

            String finalKey = key;
            List<String> collect = branches.stream()
                .filter(f -> {
                    if (leftLike && rightLike) {
                        return finalNeedMatchMainBranch ? f.contains(mainBranch) && f.contains(
                            finalKey) : f.contains(finalKey);
                    }
                    if (leftLike) {
                        return finalNeedMatchMainBranch ? f.contains(mainBranch) && f.endsWith(
                            finalKey) : f.endsWith(finalKey);
                    }
                    if (rightLike) {
                        return finalNeedMatchMainBranch ? f.contains(mainBranch) && f.startsWith(
                            finalKey) : f.startsWith(finalKey);
                    }
                    return Boolean.FALSE;
                }).collect(
                    Collectors.toList());
            if (CollectionUtil.isEmpty(collect)) {
                needMatchMainBranch = false;
                if (i == keyWords.size() - 1) {
                    // 最后一个,还匹配失败就返回全部的
                    waitSelectList.addAll(branches);
                } else {
                    continue;
                }
            }

            if (CollectionUtil.isNotEmpty(collect)) {
                if (collect.size() > 1) {
                    // 多个测试分支，需要用户选择
                    waitSelectList.addAll(collect);
                } else {
                    // 只有一个测试分支
                    searchBranch = collect.get(0);
                }
                break;
            }
        }

        if (CollectionUtil.isNotEmpty(waitSelectList)) {
            LogUtil.error(
                "在项目【{}】的主分支 {} 下，检测到多个 [{}分支] ，请输入下面列出的分支名称进行选择(若无列出则请把远程git仓库的分支拉取到本地git仓库，再次操作分析 or 输入 ignore)",
                projectName, mainBranch, jobName);
            waitSelectList.forEach(f -> LogUtil.printf(" - {}", f));

            while (true) {
                Scanner scanner = new Scanner(System.in);
                String next = scanner.next();
                if ("ignore".equals(next)) {
                    return null;
                }
                if (waitSelectList.contains(next)) {
                    searchBranch = next;
                    break;
                }
                LogUtil.error(
                    "在项目【{}】的主分支 {} 下，请选择上面列出的 [{}分支] 名称(若无则请把远程git仓库的分支拉取到本地git仓库，再次操作分析 or 输入 ignore)",
                    projectName, mainBranch, jobName);
            }
        }
        return searchBranch;
    }


    /**
     * 打印存档信息
     *
     * @param jsonConfigInfo  JSON 配置信息
     * @param matchedBranches 匹配分支  （目前只支持匹配到一个分支）
     * @param localGitRepos   本地 Git 存储库
     */
    public static void printArchiveInfo(String projectJsonPath, JsonConfigInfo jsonConfigInfo,
        List<String> matchedBranches,
        List<String> localGitRepos) {
        // 匹配到的开发分支
        String matchBranch = matchedBranches.get(0);
        List<ProjectInfo> projectConfigs = jsonConfigInfo.getProjectConfigs();
        Map<String, ProjectInfo> projectInfoMap = projectConfigs.stream()
            .collect(Collectors.toMap(ProjectInfo::getProjectGitUrl, v -> v));

        // TODO:魔法值优化
        Map<String/*serviceType*/, String/*template*/> templateMap = FileUtil.loadContentByPath(
            "src/main/java/com/source/auto/config/excel-template.txt");

        List<String> apiList = new ArrayList<>();
        List<String> serviceList = new ArrayList<>();
        List<String> webList = new ArrayList<>();

        boolean needStuffJson = false;
        for (String localGitRepo : localGitRepos) {
            // 项目远程git url
            String repoUrl = GitUtil.getRepoUrl(localGitRepo);
            String gitUserName = GitUtil.getGitUserName(localGitRepo);
            // TODO:开发分支匹配主分支 (匹配规则支持配置)
            ProjectInfo projectInfo = projectInfoMap.get(repoUrl);
            if (projectInfo == null) {
                LogUtil.error(
                    "[请配合接下来的json文件更新...]根据分支匹配到的项目信息未在json文件中 git url={}",
                    repoUrl);
                projectInfo = BizUtil.refreshJsonConfigInfo(localGitRepo);
                jsonConfigInfo.getProjectConfigs().add(projectInfo);
                needStuffJson = true;
            }
            List<BranchInfo> branchInfos = projectInfo.getBranchInfos();

            // 匹配主分支
            String mainBranch = "";
            String testBranch = "";
            List<BranchInfo> mainBranList = branchInfos.stream()
                .filter(f -> matchBranch.contains(f.getMainBranch())).distinct().collect(
                    Collectors.toList());

            // 特殊规则
            if (CollectionUtil.isEmpty(mainBranList)) {
                if (matchBranch.contains("dd_master")) {
                    mainBranList = branchInfos.stream()
                        .filter(f -> "master".equals(f.getMainBranch())).distinct().collect(
                            Collectors.toList());
                }
            }

            if (CollectionUtil.isEmpty(mainBranList)) {
                LogUtil.error(
                    "项目【{}】根据开发分支 {} 匹配不到对应的主分支，请自行填写(下面是当前项目的主分支列表供参考)",
                    projectInfo.getProjectName(), matchBranch);
                // 当前项目主分支列表
                projectInfo.getBranchInfos().stream().map(BranchInfo::getMainBranch).distinct()
                    .forEach(f -> LogUtil.printf(" - {}", f));

                Scanner scanner1 = new Scanner(System.in);
                mainBranch = scanner1.next();

                LogUtil.error("请自行填写对应的测试分支");
                Scanner scanner2 = new Scanner(System.in);
                testBranch = scanner2.next();
            } else if (mainBranList.size() == 1) {
                mainBranch = mainBranList.get(0).getMainBranch();
                testBranch = mainBranList.get(0).getTestMergeBranch();
            } else if (mainBranList.size() > 1) {
                LogUtil.error("项目【{}】根据开发分支 {} 匹配到多个主分支，请自行选择",
                    projectInfo.getProjectName(), matchBranch);
                mainBranList.forEach(f -> LogUtil.printf(" - {}", f.getMainBranch()));
                while (true) {
                    Scanner scanner3 = new Scanner(System.in);
                    String next = scanner3.next();
                    if (mainBranList.stream().anyMatch(f -> f.getMainBranch().equals(next))) {
                        mainBranch = next;
                        break;
                    }
                    LogUtil.error("请输上面列出来的主分支信息");
                }
                String finalMainBranch = mainBranch;
                List<BranchInfo> collect = mainBranList.stream()
                    .filter(f -> f.getMainBranch().equals(finalMainBranch)).collect(
                        Collectors.toList());
                BranchInfo branchInfo = collect.get(0);
                testBranch = branchInfo.getTestMergeBranch();
            }

            // 有改动的服务名字列表
            Set<String> changServiceNameList = new HashSet<String>();

            // 获取改动文件全路径
            List<String> changedFilesWithFullPath = GitUtil.getChangedFilesWithFullPath(
                localGitRepo, matchBranch, mainBranch);

            // 打印改动文件全路径
            if (changedFilesWithFullPath.isEmpty()) {
                LogUtil.printf("项目【{}】,当前开发分支 {} 和主分支 {} 相对比 无任何改动",
                    projectInfo.getProjectName(), matchBranch,
                    mainBranch);
            } else {
                for (String file : changedFilesWithFullPath) {
                    Set<String> collect = projectInfo.getServices().stream()
                        .filter(f -> file.contains("\\" + f.getServiceName() + "\\")).map(
                            ServiceInfo::getServiceName).collect(
                            Collectors.toSet());
                    if (CollectionUtil.isNotEmpty(collect)) {
                        changServiceNameList.addAll(collect);
                    }
                }
            }

            for (ServiceInfo service : projectInfo.getServices()) {

                // 判断是否涉及改动
                if (CollectionUtil.isEmpty(changServiceNameList)) {
                    continue;
                }
                if (!changServiceNameList.contains(service.getServiceName())) {
                    // 不涉及改动
                    continue;
                }

                ExcelTemplateInfo info = new ExcelTemplateInfo();
                info.setServiceName(service.getServiceName());
                info.setBaseService(service.getBaseService() ? "是" : "否");
                info.setApplicableEnvironment(service.getApplicableEnvironment());
                info.setPrivatizationCustomization(
                    service.getPrivatizationCustomization() ? "是" : "否");
                info.setNewService(service.getNewService() ? "是" : "否");
                info.setMainBranch(mainBranch);
                info.setTestMergeBranch(testBranch);
                info.setCurrDevBranch(matchBranch);
                info.setArchitectureType(service.getArchitectureType());
                info.setOwner(
                    StrUtil.isEmpty(service.getOwner()) ? gitUserName : service.getOwner());

                switch (service.getServiceType()) {
                    case "api":
                        apiList.add(info.getApiExcelInfo(templateMap.get("api")));
                        break;
                    case "service":
                        serviceList.add(info.getServiceExcelInfo(templateMap.get("service")));
                        break;
                    case "web":
                        webList.add(info.getWebExcelInfo(templateMap.get("web")));
                        break;
                }
            }
        }

        if (needStuffJson) {
            // 重写json文件保存到本地
            String jsonStr = JSONUtil.toJsonStr(jsonConfigInfo);
            LogUtil.printf(jsonStr);
            FileUtil.overwriteFile(projectJsonPath, jsonStr);
        }

        // 顺序调整，如果有core，就core放在最前面 magicube-core、fishnet-core最前面
        if (CollectionUtil.isNotEmpty(serviceList)) {
            serviceList.sort(Comparator.comparingInt(BizUtil::getPriority));
        }

        // 打印归档信息
        LogUtil.printf("\n(任务完成)可复制下面的归档信息：");
        if (CollectionUtil.isNotEmpty(apiList)) {
            LogUtil.printf("\n=======⭐Api=======");
            apiList.sort(Comparator.comparingInt(BizUtil::getPriority));
            apiList.forEach(LogUtil::printfMaster);
            LogUtil.printf("===================");
        }
        if (CollectionUtil.isNotEmpty(serviceList) || CollectionUtil.isNotEmpty(webList)) {
            LogUtil.printf("\n=======⭐Service & ⭐Web=======");
            serviceList.forEach(LogUtil::printfMaster);
            webList.forEach(LogUtil::printfMaster);
            LogUtil.printf("===============================");

        }
    }

    /**
     * 获取优先权 越小越靠前
     *
     * @param o o
     * @return int
     */
    public static int getPriority(String o) {
        if (o.contains("magicube-core")) {
            return -3;
        } else if (o.contains("fishnet-core")) {
            return -2;
        } else if (o.contains("core")) {
            return -1;
        }
        return 0;
    }

}
